package com.hotel.config.rabbitmq.customer;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.common.status.RedisKey;
import com.common.status.ResultMsg;
import com.common.utils.LocalDateTimeToTimeStamp;
import com.hotel.config.websocket.WebSocketProcess;
import com.hotel.couponsystem.mapper.CouponStockMapper;
import com.hotel.couponsystem.pojo.CouponStock;
import com.hotel.couponsystem.service.CouponStockService;
import com.hotel.customersystem.mapper.CustomerUserCouponMapper;
import com.hotel.customersystem.pojo.CustomerUserCoupon;
import com.hotel.hotelsystem.pojo.vo.CouponVo;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

import static com.hotel.config.rabbitmq.config.DelayConfig.*;

/**
 * 处理优惠券消费者
 */
@Slf4j
@Component
public class CustomerCoupon {

    // 消息推送组件
    @Resource
    private WebSocketProcess webSocketProcess;

    // 消息队列组件
    @Resource
    private RabbitTemplate rabbitTemplate;

    @Resource
    private RedisTemplate redisTemplate;

    // 个人中心优惠券
    @Resource
    private CustomerUserCouponMapper customerUserCouponMapper;

    @Resource
    private CouponStockMapper couponStockMapper;

    @Resource
    private CouponStockService couponStockService;

    /**
     * 延时队列、死信队列解决秒杀问题
     * @param couponVo
     */
    @Transactional
    @RabbitHandler
    @RabbitListener(queues = SECKIL_COUPON_QUEUE)
    public void seckilCoupon(CouponVo couponVo,Channel channel,Message message) throws Exception {
        log.info("优惠券对象： {}",couponVo);
        String uuid = UUID.randomUUID().toString();
        // 设置分布式锁                        判断是否有该锁                 锁              0.1秒后自动释放
        Boolean flag = redisTemplate.opsForValue().setIfAbsent(RedisKey.LOCK,uuid,100, TimeUnit.MILLISECONDS); // 判断该key是否存在与redis缓存中
        if (flag) { // 如果该锁存在
            // 查询缓存中抢购到的优惠券记录
            Object o = redisTemplate.boundValueOps(RedisKey.ISSECKILCOUPON).get();
            log.info("缓存中的锁： {}",o);
            if (o == null) {
                // 走消息推送
                webSocketProcess.sendMessage(couponVo.getUserAdmin(),"加载失败，请重新抢购");
//                return;
            }
            // 1.先判断库存表中的优惠券数量是为空
            LambdaQueryWrapper<CouponStock> stockQuery = new LambdaQueryWrapper<>();
            stockQuery.eq(CouponStock::getCouponNo,couponVo.getCouponNo());
            CouponStock couponStock = couponStockMapper.selectOne(stockQuery);
            if (couponStock.getStock() == 0) { // 库存不为空
                webSocketProcess.sendAllMessage("优惠券库存量不足，活动结束!");
                return;
            }
            // 封装优惠券对象
            CustomerUserCoupon coupon = new CustomerUserCoupon();
            coupon.setCouponNo(couponVo.getCouponNo()); // 优惠券编号
            coupon.setCouponUseStatus(0); // 使用状态
//            coupon.setUserId(couponVo.getUserId());
            coupon.setStandby02(uuid); // 库存编号
            coupon.setStandby01(couponVo.getUserAdmin());
            coupon.setStock(1);
            coupon.setReceiveTime(couponVo.getReceiveTime());
            coupon.setInvalidTime(couponVo.getInvalidTime());
            // 插入前先判断用户优惠券库存表中是否已有该优惠券
            LambdaQueryWrapper<CustomerUserCoupon> lbq = new LambdaQueryWrapper<>();
            lbq.eq(CustomerUserCoupon::getCouponNo,coupon.getCouponNo()).eq(CustomerUserCoupon::getStandby01,coupon.getStandby01());
            CustomerUserCoupon one = customerUserCouponMapper.selectOne(lbq);
            log.info("库存中优惠券记录:{}",one);
            if (one != null) {
                // 消息推
                webSocketProcess.sendMessage(couponVo.getUserAdmin(),"你已有该优惠券，不能再抢购!");
                return;
            }
            // 修改优惠券库存表记录
            LambdaQueryWrapper<CouponStock> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(CouponStock::getCouponNo,coupon.getCouponNo());
            String msg = couponStockService.reduceCouponStock(couponVo.getCouponNo());
            if (msg.equals(ResultMsg.SECKIL_COUPON_SUCCESS)) {
                // 个人中心插入优惠券记录
                Integer rows = customerUserCouponMapper.insert(coupon);
                // 计算时间差
                long time = (LocalDateTimeToTimeStamp.localDateTimeToTimeStamp(coupon.getInvalidTime()) - (LocalDateTimeToTimeStamp.localDateTimeToTimeStamp(coupon.getReceiveTime())));
                log.info("时间戳：{}",time);
                // 给生产者发送消息
                rabbitTemplate.convertAndSend(DELAYED_COUPON_EXCHANGE,DELAYED_COUPON_ROUTER_KEY,coupon,delayMag->{
                    delayMag.getMessageProperties().setDelay(Math.toIntExact(time)); // 转成int类型
                    return delayMag;
                });
                if (rows > 0) {
                    redisTemplate.opsForValue().set(RedisKey.ISSECKILCOUPON,rows > 0); // 将抢购到的记录存入到缓存中
                    // 删除当日优惠券缓存中的值
                    redisTemplate.delete(RedisKey.TODAYCOUPONLIST);
                    // 如果缓存中的值相同，就根据key删除缓存中的值 即 释放缓存
                    if (uuid.equals(redisTemplate.boundValueOps(RedisKey.LOCK))) redisTemplate.delete(RedisKey.LOCK);
                }
            } else {
                // 每隔0.1秒获取一次
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            // 通知消息队列
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        }
    }

    // 死信队列
    @RabbitHandler
    @RabbitListener(queues = DEAD_COUPON_QUEUE)
    public void dealDeadQueue(CustomerUserCoupon coupon) throws Exception {
        log.info("消息体：{}",coupon);
        // 通知用户秒杀失败
        webSocketProcess.sendMessage(coupon.getStandby01(),"秒杀失败");
    }

    // 延迟队列
    @RabbitHandler
    @RabbitListener(queues = DELAYED_COUPON_QUEUE)
    public void dealDelayQueue(CustomerUserCoupon coupon) throws Exception {
        log.info("优惠券信息：{}",coupon);
        // 计算优惠券时间差
        System.out.println(LocalDateTimeToTimeStamp.localDateTimeToTimeStamp(coupon.getInvalidTime()));
        Integer row = customerUserCouponMapper.updateByCouponNo(Integer.valueOf(coupon.getCouponNo())); // 修改优惠券过期状态
        if (row>0) webSocketProcess.sendMessage(coupon.getStandby01(), coupon.getCouponNo()+"优惠券已过期");
    }
}
